﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.Windows.Forms.DataVisualization.Charting;

using CtpApi.Struct;
using CtpApi.CtpInterface;

using TraderClient.Models;
using TraderClient.Views;
using TraderClient.Views.Trade;
using TraderClient.Logic.PolicyCenter;
using TraderClient.Logic.QuotationsCenter;

namespace TraderClient
{
    public partial class MainForm : Form
    {
        private TradeApi tdApi;
        private QuoteManager quotations;
        private ChartCandlestick chart;
        private Series seriesCandlestick;

        public MainForm()
        {
            InitializeComponent();
        }

        private Hashtable hashTable = new Hashtable();
        private string[] subscribedInstruments;

        public void FlushDisplayInstrument()
        {
            dataGridViewPriceList.AutoGenerateColumns = false;
            dataGridViewPriceList.Columns.Add("InstrumentID", "合约代码");
            dataGridViewPriceList.Columns.Add("LastPrice", "最新价");

            dataGridViewPriceList.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
            dataGridViewPriceList.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;

            dataGridViewPriceList.Columns[0].DefaultCellStyle.ForeColor = Color.Yellow;
            dataGridViewPriceList.Columns[1].DefaultCellStyle.ForeColor = Color.White;

            TraderClient.Models.DisplayInstruments[] instruments = WAF.EntityFramework.EntityAction.Select<TraderClient.Models.DisplayInstruments>();

            subscribedInstruments = new string[instruments.Length];

            for (int i = 0; i < instruments.Length; i++)
            {
                subscribedInstruments[i] = instruments[i].InstrumentID;

                int index = dataGridViewPriceList.Rows.Add(instruments[i].InstrumentID, 0);
                hashTable.Add(instruments[i].InstrumentID, index);                
            }
        }

        /// <summary>
        /// 双击Tab控件显示和隐藏账户信息等
        /// </summary>
        private void ViewTabControl()
        {
            splitContainerTab.Panel2Collapsed = !splitContainerTab.Panel2Collapsed;

            if (!splitContainerTab.Panel2Collapsed)
                splitContainerTab.SplitterDistance = splitContainerTab.Height - 140;
        }

        /// <summary>
        /// 用默认颜色显示状态栏信息
        /// </summary>
        /// <param name="message">信息文本</param>
        private void DisplayStatusMessage(string message)
        {
            DisplayStatusMessage(Color.Black, message);
        }

        /// <summary>
        /// 用指定颜色显示状态栏信息
        /// </summary>
        /// <param name="color">字体颜色</param>
        /// <param name="message">信息文本</param>
        private void DisplayStatusMessage(Color color, string message)
        {
            toolStripStatusLabelMessage.ForeColor = color;
            toolStripStatusLabelMessage.Text = "【" + DateTime.Now.ToString("hh:mm:ss") + "】" + message;
        }



        /// <summary>
        /// 将响应对象实体绑定到指定Grid，绑定后将清除列表
        /// </summary>
        /// <param name="grid">要绑定的DataGridView</param>
        /// <param name="list">响应对象实体列表</param>
        private void BindGridDataSource(DataGridView grid, ArrayList list)
        {
            grid.Rows.Clear();

            if (list.Count > 0)
            {
                Type fieldType = list[0].GetType();
                PropertyInfo[] pInfos = fieldType.GetProperties();

                foreach (object field in list)
                {
                    int newrow = grid.Rows.Add(1);
                    DataGridViewRow row = grid.Rows[newrow];

                    foreach (DataGridViewColumn col in grid.Columns)
                    {
                        //Grid的字段名需用控件名加‘_’组成
                        string colName = col.Name.Split('_')[1];
                        PropertyInfo pInfo = fieldType.GetProperty(colName);

                        if (pInfo != null)
                            row.Cells[col.Name].Value = fieldType.GetProperty(colName).GetValue(field, null);
                    }
                }

                list.Clear();
            }
        }


        /************************* 交易接口事件 *************************/

        #region 交易接口事件

        //注册交易接口事件
        private void InitTradeApi()
        {
            string borkerID = "4030";
            string userID   = "80002863";
            string password = "888888";

            string[] frontTd  = { @"tcp://asp-sim2-front1.financial-trading-platform.com:26205" };

            tdApi = new TradeApi(borkerID, userID, password, frontTd);

            tdApi.RtnOrder += OnRtnOrder;
            tdApi.RtnTrade += OnRtnTrade;
            tdApi.RtnInstrumentStatus += OnRtnInstrumentStatus;

            tdApi.ErrRtnOrderInsert += OnErrRtnOrderInsert;
            tdApi.ErrRtnOrderAction += OnErrRtnOrderAction;

            tdApi.RspOrderInsert += OnRspOrderInsert;
            tdApi.RspOrderAction += OnRspOrderAction;

            tdApi.RspQryOrder += OnRspQryOrder;
            tdApi.RspQryTrade += OnRspQryTrade;
            tdApi.RspQryTradingAccount += OnRspQryTradingAccount;
            tdApi.RspQryInvestorPosition += OnRspQryInvestorPosition;
            tdApi.RspQryInvestorPositionDetail += OnRspQryInvestorPositionDetail;
        }


        //报单响应
        void OnRtnOrder(CThostFtdcOrderField pOrder)
        {
            if (pOrder != null)
            {
                Action ac = () =>
                {
                    string msg = pOrder.InstrumentID + "->" + pOrder.CombOffsetFlag + "->" + pOrder.StatusMsg;
                    DisplayStatusMessage(msg);
                };

                this.Invoke(ac);
            }
        }

        //报单成交通知
        void OnRtnTrade(CThostFtdcTradeField pTrade)
        {
            if (pTrade != null)
            {
                Action ac = () =>
                {
                    tdApi.QryInvestorPositionDetail();
                };

                this.Invoke(ac);
            }
        }

        //报单录入请求响应
        void OnRspOrderInsert(CThostFtdcInputOrderField pInputOrder, CThostFtdcRspInfoField pRspInfo, int nRequestID, bool bIsLast)
        {
            if (pRspInfo != null)
            {
                Action<CThostFtdcRspInfoField> ac = (field) =>
                {
                    DisplayStatusMessage(Color.Red, field.ErrorMsg);
                };

                this.Invoke(ac, pRspInfo);
            }
        }

        //报单操作请求响应
        void OnRspOrderAction(CThostFtdcInputOrderActionField pInputOrderAction, CThostFtdcRspInfoField pRspInfo, int nRequestID, bool bIsLast)
        {
            if (pRspInfo != null)
            {
                Action<CThostFtdcRspInfoField> ac = (field) =>
                {
                    DisplayStatusMessage(Color.Red, field.ErrorMsg);
                };

                this.Invoke(ac, pRspInfo);
            }
        }

        //报单录入错误回报
        void OnErrRtnOrderInsert(CThostFtdcInputOrderField pInputOrder, CThostFtdcRspInfoField pRspInfo)
        {
            if (pRspInfo != null)
            {
                Action<CThostFtdcRspInfoField> ac = (field) =>
                {
                    DisplayStatusMessage(Color.Red, field.ErrorMsg);
                };

                this.Invoke(ac, pRspInfo);
            }
        }

        //报单操作错误回报
        void OnErrRtnOrderAction(CThostFtdcOrderActionField pOrderAction, CThostFtdcRspInfoField pRspInfo)
        {
            if (pRspInfo != null)
            {
                Action<CThostFtdcRspInfoField> ac = (field) =>
                {
                    DisplayStatusMessage(Color.Red, field.ErrorMsg);
                };

                this.Invoke(ac, pRspInfo);
            }
        }

        //请求查询报单响应
        private ArrayList qryOrders = new ArrayList();
        void OnRspQryOrder(CThostFtdcOrderField pOrder, CThostFtdcRspInfoField pRspInfo, int nRequestID, bool bIsLast)
        {
            if (pOrder != null)
                qryOrders.Add(pOrder);

            if( bIsLast )
            {
                Action ac = () =>
                {
                    BindGridDataSource(gridOrder, qryOrders);
                };

                this.Invoke(ac);
            }
            
        }

        //请求查询成交响应
        void OnRspQryTrade(CThostFtdcTradeField pTrade, CThostFtdcRspInfoField pRspInfo, int nRequestID, bool bIsLast)
        {
            if (pTrade != null)
            {
                Action<CThostFtdcTradeField> ac = (field) =>
                {
                    
                };

                this.Invoke(ac, pTrade);
            }
        }

        //查询资金账户响应
        private void OnRspQryTradingAccount(CThostFtdcTradingAccountField pTradingAccount, CThostFtdcRspInfoField pRspInfo, int nRequestID, bool bIsLast)
        {
            if (pTradingAccount == null) return;

            Action<CThostFtdcTradingAccountField> ac = (account) =>
            {
                BindGridDataSource(gridAccount, new ArrayList() { account });
            };

            this.Invoke(ac, pTradingAccount);
        }

        //查询投资者持仓响应
        private ArrayList positions = new ArrayList();
        private void OnRspQryInvestorPosition(CThostFtdcInvestorPositionField pInvestorPosition, CThostFtdcRspInfoField pRspInfo, int nRequestID, bool bIsLast)
        {
            if (pInvestorPosition == null) return;

            positions.Add(pInvestorPosition);

            if (bIsLast)
            {
                Action ac = () =>
                {
                    BindGridDataSource(gridPosition, positions);
                };

                this.Invoke(ac);
            }
        }

        //查询投资者持仓明细响应
        private ArrayList positionDetails = new ArrayList();
        void OnRspQryInvestorPositionDetail(CThostFtdcInvestorPositionDetailField pInvestorPositionDetail, CThostFtdcRspInfoField pRspInfo, int nRequestID, bool bIsLast)
        {
            if (pInvestorPositionDetail == null) return;

            if(pInvestorPositionDetail.Volume != 0)
                positionDetails.Add(pInvestorPositionDetail);

            if (bIsLast)
            {
                Action ac = () =>
                {
                    BindGridDataSource(gridPosition, positionDetails);
                };

                this.Invoke(ac);
            }
        }

        //合约交易状态通知
        void OnRtnInstrumentStatus(CThostFtdcInstrumentStatusField pInstrumentStatus)
        {
            if (pInstrumentStatus != null)
            {
                Action<CThostFtdcInstrumentStatusField> ac = (instrumentStatus) =>
                {
                    string msg = instrumentStatus.EnterTime + " : " + instrumentStatus.InstrumentStatus.ToString();
                    toolStripStatusLabelExchangeStatus.Text = msg;
                };

                this.Invoke(ac, pInstrumentStatus);
            }
        }

        #endregion


        /************************* 窗体事件 *************************/

        private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            tdApi.Release();
            QuoteManager.Release();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            FlushDisplayInstrument();

            InitTradeApi();

            ViewTabControl();


            gridAccount.AutoGenerateColumns     = false;
            gridPosition.AutoGenerateColumns    = false;
            gridOrder.AutoGenerateColumns  = false;

            displayLastPrice = new DisplayLastPriceDelegate(DisplayLastPrice);

            int[] levels = new int[] { 1, 5, 10 };
            QuoteManager.SetQuote(subscribedInstruments, levels);
            quotations = QuoteManager.GetInstance();

            quotations.KLineOpen        += OnKLineOpen;
            quotations.KLinePriceChange += OnLastPriceArrive;

            PolicyManager policy = new PolicyManager();

            chart = new ChartCandlestick(this.splitContainer.Panel2);

            foreach (string code in subscribedInstruments)
            {
                foreach (int i in levels)
                {
                    chart.CreateSeries(code + "_" + i.ToString());
                }
            }

            chart.GetSeries("SR209_1").ChartArea = chart.ChartAreaName;
        }

        void OnKLineOpen(KLineSeries series)
        {
            Action ac = () =>
            {
                KLine kline = series.LastKLine;
                Series chartSeries = chart.GetSeries(series.Code + "_" + series.Level.ToString());
                chartSeries.Points.AddXY(kline.OpenTime, kline.High, kline.Low, kline.Open, kline.Close);
            };

            this.Invoke(ac);
        }

        /// <summary>
        /// 最新价格到达处理
        /// </summary>
        /// <param name="instrumentID">合约代码</param>
        /// <param name="kLines">K线数组</param>
        void OnLastPriceArrive(KLineSeries series)
        {
            Action ac = () =>
            {
                KLine kline = series.LastKLine;
                Series chartSeries = chart.GetSeries(series.Code + "_" + series.Level.ToString());
                chartSeries.Points[chartSeries.Points.Count - 1].SetValueY(kline.High, kline.Low, kline.Open, kline.Close);

                DisplayLastPrice(series.Code, series.LastKLine);
            };

            this.Invoke(ac);

            if (series.Level == 1)
            {
                //if(this != null && !this.Disposing)
                    //this.Invoke(displayLastPrice, series.Code, series.LastKLine);
            }
        }

        private DisplayLastPriceDelegate displayLastPrice;
        private delegate void DisplayLastPriceDelegate(string instrumentID, KLine kLine);

        private void DisplayLastPrice(string instrumentID, KLine kLine)
        {
            int rowIndex = (int)hashTable[instrumentID];
            DataGridViewCell cell = dataGridViewPriceList.Rows[rowIndex].Cells[1];

            cell.Value = kLine.Close;

            if (cell.Style.ForeColor == Color.White)
                cell.Style.ForeColor = Color.Gray;
            else
                cell.Style.ForeColor = Color.White;

            if (selectedInstrumentID == instrumentID)
            {
                labelInstrumentID.Text = instrumentID;
                labelLashPrice.Text = kLine.Close.ToString();
            }
        }

        //软件登录密码及数据库连接设置
        private void toolStripButtonLogin_Click(object sender, EventArgs e)
        {
            //BasicDataForm bdf = new BasicDataForm();
            //bdf.ShowDialog();

            InstrumentInfo form = new InstrumentInfo();
            form.ShowInTaskbar = false;
            form.Show();
        }

        //导入数据
        private void toolStripButtonInputData_Click(object sender, EventArgs e)
        {
            //InputData inputdata = new InputData();
            //inputdata.Show();
        }

        /*
        private void viewKLine()
        {
            //设置数据
            DateTime start = new DateTime(2011, 9, 28);
            DateTime end = new DateTime(2011, 9, 29);
            List<KData> kDatas = KLineData.GetKLineData("SR", 1, KLineUnit.Minutes, start, end);

            ChartCandlestick chart = new ChartCandlestick(this.splitContainer.Panel2);
            Series seriesCandlestick = chart.CreateSeries("candlestick");

            //数据序列样式
            seriesCandlestick.ChartArea = "Candlestick";
            seriesCandlestick.ChartType = SeriesChartType.Candlestick;
            seriesCandlestick.IsXValueIndexed = true;
            seriesCandlestick.XValueType = ChartValueType.DateTime;

            //k线颜色
            seriesCandlestick.SetCustomProperty("PriceUpColor", "Red");
            seriesCandlestick.SetCustomProperty("PriceDownColor", "Aquamarine");

            foreach (KData kData in kDatas)
            {
                seriesCandlestick.Points.AddXY(KLineData.FromLongToDateTime(kData.KDatetime), kData.High, kData.Low, kData.Open, kData.Close);
            }

            ArrowAnnotation aa = new ArrowAnnotation();
            aa.X = double.NaN;
            aa.Y = double.NaN;
            aa.AnchorX = double.NaN;
            aa.AnchorY = double.NaN;
            aa.ArrowStyle = ArrowStyle.Tailed;
            aa.ArrowSize = 10;
            aa.BackColor = Color.White;
            aa.Visible = true;
            aa.AnchorDataPoint = seriesCandlestick.Points[10];

            chart.CreateAnnotation(aa);

            chart.Display();
        }
        */

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            //tdApi.QryTradingAccount();
            
            tdApi.QryInvestorPositionDetail();
        }

        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            ViewTabControl();
        }

        private void btnBuy_Click(object sender, EventArgs e)
        {
            tdApi.Buy(selectedInstrumentID, (double)numericUpDownTradePrice.Value, (int)numericUpDownVolume.Value);
        }

        private void btnSell_Click(object sender, EventArgs e)
        {
            tdApi.Sell(selectedInstrumentID, (double)numericUpDownTradePrice.Value, (int)numericUpDownVolume.Value);
        }

        private void tabControl_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            int index = ((TabControl)sender).SelectedIndex;

            if (index == 0)
                tdApi.QryTradingAccount();
            else if (index == 1)
                tdApi.QryInvestorPositionDetail();
            else if (index == 2)
                tdApi.QryOrder();
            
            //splitContainerTrade.Panel1Collapsed = !splitContainerTrade.Panel1Collapsed;
        }

        private void gridPosition_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            DataGridViewRow row = gridPosition.Rows[e.RowIndex];

            string instrumentID = row.Cells["gridPosition_InstrumentID"].Value.ToString();
            double price = double.Parse(numericUpDownTradePrice.Value.ToString());
            int volume = int.Parse(row.Cells["gridPosition_Volume"].Value.ToString());
            string openDate = row.Cells["gridPosition_OpenDate"].Value.ToString();

            DirectionEnum diretion = row.Cells["gridPosition_Direction"].Value.ToString() == "Buy" ? DirectionEnum.Sell : DirectionEnum.Buy;

            if (openDate != DateTime.Now.ToString("yyyyMMdd"))
            {
                tdApi.Close(diretion, instrumentID, price, volume);
            }
            else
            {
                tdApi.CloseToday(diretion, instrumentID, price, volume);
            }
        }

        /// <summary>
        /// 当前选中的合约代码
        /// </summary>
        private string selectedInstrumentID;

        private void dataGridViewPriceList_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            selectedInstrumentID = dataGridViewPriceList.Rows[e.RowIndex].Cells[0].Value.ToString();
            string pricestring = dataGridViewPriceList.Rows[e.RowIndex].Cells[1].Value.ToString();
            decimal price = decimal.Parse(pricestring);

            labelInstrumentID.Text = selectedInstrumentID;
            labelLashPrice.Text = pricestring;
            numericUpDownTradePrice.Value = price; 
        }
    }
}
